home *** CD-ROM | disk | FTP | other *** search
- /*
- * fltrfreq.c
- *
- * Practical Algorithms for Image Analysis
- *
- * Copyright (c) 1997, 1998, 1999 MLMSoftwareGroup, LLC
- */
-
- /* FLTRFREQ: program performs lowpass, highpass, bandpass, or bandstop
- * filtering on image by applying filter in frequency domain
- * usage: fltrfreq inimg outimg [-l f1] [-h f1] [-b f1 f2]
- * [-s f1 f2] [-n ORDER] [-g] [-p] [-I] [-L]
- * Note: Low/High-pass frequencies are specified as fraction of 1,
- * where 1 is normalized highest frequency.
- * Note: image sidelength must be power of 2; if not the case,
- * this program changes the size to be so, either the
- * next higher or lower power of 2 as user-chosen (<-p>).
- *
- */
-
- #include <stdio.h>
- #include <math.h>
- #include <stdlib.h>
- #include <malloc.h>
- #include <string.h>
-
- #include "ip.h"
-
- #if defined(WIN32) || defined(LINUX)
- #define M_PI 3.14159265358979323846
- #define log2(a) (log(a)/ 0.6931471805599)
- #define exp2(a) (pow((double)2, (double)a))
- #endif
- #define PASS_TYPE_DFLT 0 /* default filter passband is low-pass */
- #define F1_DFLT 0.5 /* default filter cutoff is half */
- #define F2_DFLT 0.0
- #define ORDER_DFLT 1 /* default order of Butterworth filter */
- #define BUTTERWORTH 1 /* Butterworth filter type */
- #define GAUSSIAN 2 /* Gaussian filter type */
-
- void input (int argc, char *argv[], short *passType, double *f1, double *f2, double *order, short *fltrType, short *zeroPad, long *invertFlag);
- void window (float **image, long nRow, long nCol, long nRowS, long nColS);
- void usage (short flag);
-
- main (argc, argv)
- int argc;
- char *argv[];
-
- {
- register long x, y, nCol, nRow, /* image input sidelengths */
- nCol2, nRow2; /* power of 2 spectrum sidelengths */
- // nColD2, nRowD2; /* middle row/column of spectrum image */
- long xStart, yStart; /* beginning coord.s of pow spec in image */
- Image *imgI, *imgO; /* I/O image structures */
- unsigned char **imgIn, /* image array */
- **imgOut; /* output image */
- short passType; /* lowpass=0, high=1, band=2, stop=3 */
- double f1, f2; /* 3dB frequency bounds of filter */
- double order; /* order of Butterworth filter */
- short fltrType; /* Butterworth or Gaussian filter type */
- short zeroPad; /* if 1, upsize image to pow of 2; 0 => down */
- float **imgReal, **imgImag; /* complex image arrays */
- //float *wndwX, *wndwY; /* row and column window vectors */
- double min, max; /* maximum value in power spectrum */
- float max0, min0; /* initial max,min values of image */
- double norm; /* normalization factor for img intensities */
- double temp;
- long invertFlag;
- //double sqrt (), log2 (), log10 (), exp2 ();
-
- input (argc, argv, &passType, &f1, &f2, &order, &fltrType, &zeroPad, &invertFlag);
-
- /* read input image */
- imgI = ImageIn (argv[1]);
- imgIn = imgI->img;
- nRow = ImageGetHeight (imgI);
- nCol = ImageGetWidth (imgI);
- printf ("Original image is %3dx%3d.\n", nCol, nRow);
-
- /* invert image intensities for going into processing */
- if (invertFlag) {
- for (y = 0; y < nRow; y++)
- for (x = 0; x < nCol; x++)
- imgIn[y][x] = 255 - imgIn[y][x];
- }
-
- /* check for image sidelengths powers of 2 */
- nRow2 = nRow;
- temp = log2 ((double) nRow);
- if ((temp - (long) temp) != 0.0)
- nRow2 = (zeroPad == 0) ?
- (long) exp2 ((double) ((long) temp)) : (long) exp2 ((double) ((long) temp + 1));
- nCol2 = nCol;
- temp = log2 ((double) nCol);
- if ((temp - (long) temp) != 0.0)
- nCol2 = (zeroPad == 0) ?
- (long) exp2 ((double) ((long) temp)) : (long) exp2 ((double) ((long) temp + 1));
- if (nRow2 != nRow || nCol2 != nCol)
- printf ("Image size changed to %dx%d so power of 2 (required for FFT).\n",
- nRow2, nCol2);
-
- /* allocate output image */
- imgO = ImageAlloc (nRow2, nCol2, ImageGetDepth (imgI));
- imgOut = ImageGetPtr (imgO);
-
- /* allocate memory for complex array */
- if ((imgReal = (float **) calloc (nRow2, sizeof (float *))) == NULL)
- exit (2);
- for (y = 0; y < nRow2; y++)
- if ((imgReal[y] = (float *) calloc (nCol2, sizeof (float))) == NULL)
- exit (3);
-
- if ((imgImag = (float **) calloc (nRow2, sizeof (float *))) == NULL)
- exit (4);
- for (y = 0; y < nRow2; y++)
- if ((imgImag[y] = (float *) calloc (nCol2, sizeof (float))) == NULL)
- exit (5);
-
- /* center the image, and zero-pad or reduce size if required */
- printf ("Forward 2-D FFT being performed.\n");
- if (zeroPad == 0) {
- yStart = (nRow - nRow2) / 2;
- xStart = (nCol - nCol2) / 2;
- for (y = 0, max0 = (float) 0.0, min0 = (float) 256.0; y < nRow2; y++) {
- for (x = 0; x < nCol2; x++) {
- imgReal[y][x] = (float) imgIn[y + yStart][x + xStart];
- imgImag[y][x] = (float) 0.0;
- if (imgReal[y][x] > max0)
- max0 = imgReal[y][x];
- if (imgReal[y][x] < min0)
- min0 = imgReal[y][x];
- }
- }
- }
- else {
- yStart = (nRow2 - nRow) / 2;
- xStart = (nCol2 - nCol) / 2;
- for (y = 0; y < nRow; y++) {
- for (x = 0; x < nCol; x++) {
- imgReal[y + yStart][x + xStart] = (float) imgIn[y][x];
- imgImag[y][x] = (float) 0.0;
- }
- }
- }
-
- /* perform windowing */
- if (zeroPad == 0)
- window (imgReal, nRow2, nCol2, nRow2, nCol2);
- else
- window (imgReal, nRow2, nCol2, nRow, nCol);
-
- /* perform 2-dimensional FFT */
- fft2d (imgReal, imgImag, nRow2, nCol2, -1);
-
- /* perform filtering on frequency-domain image */
- printf ("Frequency-domain filtering being performed.\n");
- if (fltrType == BUTTERWORTH)
- fltrbttr (imgReal, imgImag, nRow2, nCol2, passType, f1, f2, order);
- else
- fltrgaus (imgReal, imgImag, nRow2, nCol2, passType, f1, f2);
-
- /* perform inverse FFT */
- printf ("Inverse 2-D FFT being performed.\n");
- fft2d (imgReal, imgImag, nRow2, nCol2, 1);
-
- /* find post-processing normalization factors for image */
- for (y = 0, min = 1000.0, max = -1000.0; y < nRow2; y++) {
- for (x = 0; x < nCol2; x++) {
- if (imgReal[y][x] < min)
- min = imgReal[y][x];
- if (imgReal[y][x] > max)
- max = imgReal[y][x];
- }
- }
- if (min > 0.0)
- min = 0.0;
- norm = max0 / (max - min);
-
- for (y = 0; y < nRow2; y++)
- for (x = 0; x < nCol2; x++)
- imgOut[y][x] = (unsigned char) ((imgReal[y][x] - min) * norm + 0.5);
-
- /* output image - un-invert it */
- if (invertFlag) {
- for (y = 0; y < nRow2; y++)
- for (x = 0; x < nCol2; x++)
- imgOut[y][x] = 255 - imgOut[y][x];
- }
-
- /* write output image */
- ImageOut (argv[2], imgO);
- return (0);
- }
-
-
- /* WINDOW: function multiplies vector by smoothing window
- * usage: window (image, nRow, nCol, nRowS, nColS)
- * Note: There are 2 sets of image sizes for the following
- * reason. The (nRow, nCol) size is the image size to be
- * windowed; that is, this is a power of 2 for the FFT.
- * The (nRowS, nColS) size is a smaller size that is the original
- * image size before zero-padding. This smaller image has
- * been placed in the middle of the zero-padded image. It is
- * the SMALLER IMAGE, NOT THE FINAL IMAGE that should be windowed.
- */
-
- void
- window (image, nRow, nCol, nRowS, nColS)
- float **image; /* image to be smoothed */
- long nRow, nCol; /* size of image to be windowed */
- long nRowS, nColS; /* size of smaller image b4 padding */
- {
- float *hammingX, *hammingY; /* horiz. and vert. hamming windows */
- double nM1; /* no. rows/cols minus 1 */
- long xStart, yStart; /* offset smaller image in larger */
- long x, y;
-
- /* allocate space for hamming windows */
- if ((hammingX = (float *) calloc (nCol, sizeof (*hammingX))) == NULL)
- exit (1);
- if ((hammingY = (float *) calloc (nRow, sizeof (*hammingY))) == NULL)
- exit (2);
-
- /* put window in middle of zeroed vector if image has been padded */
- for (x = 0; x < nCol; x++)
- hammingX[x] = (float) 0.0;
- for (y = 0; y < nRow; y++)
- hammingY[y] = (float) 0.0;
- xStart = (nCol - nColS) / 2;
- yStart = (nRow - nRowS) / 2;
-
- /* calculate Hamming window */
- nM1 = (double) (nColS - 1);
- for (x = 0; x < nColS; x++)
- hammingX[x + xStart] = (float) (0.54 - 0.46 * cos ((M_PI * 2.0 * (double) x) / nM1));
- nM1 = (double) (nRowS - 1);
- for (y = 0; y < nRowS; y++)
- hammingY[y + yStart] = (float) (0.54 - 0.46 * cos ((M_PI * 2.0 * (double) y) / nM1));
-
- /* apply window to image */
- for (y = 0; y < nRow; y++)
- for (x = 0; x < nCol; x++)
- image[y][x] = image[y][x] * hammingX[x] * hammingY[y];
-
- }
-
-
- /* USAGE: function gives instructions on usage of program
- * usage: usage (flag)
- * When flag is 1, the long message is given, 0 gives short.
- */
-
- void
- usage (flag)
- short flag; /* flag =1 for long message; =0 for short message */
- {
-
- /* print short usage message or long */
- printf ("USAGE: fltrfreq inimg outimg [-l f1] [-h f1] [-b f1 f2] \n");
- printf (" [-s f1 f2] [-n ORDER] [-g] [-p] [-I] [-L]\n");
-
- if (flag == 0)
- exit (1);
-
- printf ("\nfltrfreq performs frequency domain filtering on image.\n\n");
- printf ("ARGUMENTS:\n");
- printf (" inimg: input image filename (TIF)\n");
- printf (" outimg: output image filename (TIF)\n\n");
- printf ("OPTIONS:\n");
- printf (" -l f1: LOW-PASS FILTER passing frequencies below cutoff, f1.\n");
- printf (" -h f1: HIGH-PASS FILTER passing frequencies above cutoff, f1.\n");
- printf (" -b f1 f2: BAND-PASS FILTER passing frequencies between f1-f2.\n");
- printf (" -s f1 f2: STOP-BAND-PASS FILTER passing frequencies not f1-f2.\n");
- printf (" -n ORDER: order of Butterworth filter, dflt = %d.\n", ORDER_DFLT);
- printf (" -g: flag to perform Gaussian filter, default is Butterworth.\n");
- printf (" -p: flag for zero padding if set, and image row or column is\n");
- printf (" not a power of 2, image size is increased by zero-.\n");
- printf (" padding; otherwise image size is decreased (default).\n\n");
- printf (" NOTE -- The frequencies (f1,f2) should be expressed as a\n");
- printf (" number 0 to 1.0; this is a fractional frequency value of the\n");
- printf (" full original pass band. For example, a low-pass filter with\n");
- printf (" cutoff frequency of 0.5 will reduce the bandwidth by half.\n");
- printf (" Where the image is not square, the fractional frequency\n");
- printf (" value is relative to the higher frequency corresponding to\n");
- printf (" the longer x or y axis.\n");
- printf (" -I: invert image before processing\n");
- printf (" -L: print Software License for this module\n");
-
- exit (1);
- }
-
-
- /* INPUT: function reads input parameters
- * usage: input (argc, argv, &passType, &f1, &f2,
- * &order, &fltrType, &zeroPad)
- */
-
- void
- input (argc, argv, passType, f1, f2, order, fltrType, zeroPad, invertFlag)
- int argc;
- char *argv[];
- short *passType; /* lowpass=0, highpass=1, bandpass=2, stoppass= 3 */
- double *f1, *f2; /* 3db cutoff frequencies */
- double *order; /* order of Butterworth filter */
- short *fltrType; /* filter type */
- short *zeroPad; /* if 1, increase img size to 2-power; 0 => decrease */
- long *invertFlag; /* invert image before processing */
-
- {
- long n;
- double atof ();
-
- if (argc < 3)
- usage (1);
-
- *passType = PASS_TYPE_DFLT;
- *f1 = F1_DFLT;
- *f2 = F2_DFLT;
- *order = ORDER_DFLT;
- *fltrType = BUTTERWORTH;
- *zeroPad = 0;
- *invertFlag = 0;
-
- for (n = 3; n < argc; n++) {
- if (strcmp (argv[n], "-l") == 0) {
- if (++n == argc || argv[n][0] == '-')
- usage (0);
- *passType = 0;
- *f1 = atof (argv[n]);
- }
- else if (strcmp (argv[n], "-h") == 0) {
- if (++n == argc || argv[n][0] == '-')
- usage (0);
- *passType = 1;
- *f1 = atof (argv[n]);
- }
- else if (strcmp (argv[n], "-b") == 0) {
- if (++n == argc || argv[n][0] == '-')
- usage (0);
- *passType = 2;
- *f1 = atof (argv[n]);
- if (++n == argc || argv[n][0] == '-')
- usage (0);
- *f2 = atof (argv[n]);
- }
- else if (strcmp (argv[n], "-s") == 0) {
- if (++n == argc || argv[n][0] == '-')
- usage (0);
- *passType = 3;
- *f1 = atof (argv[n]);
- if (++n == argc || argv[n][0] == '-')
- usage (0);
- *f2 = atof (argv[n]);
- }
- else if (strcmp (argv[n], "-n") == 0) {
- if (++n == argc || argv[n][0] == '-')
- usage (0);
- *order = atof (argv[n]);
- }
- else if (strcmp (argv[n], "-g") == 0)
- *fltrType = GAUSSIAN;
- else if (strcmp (argv[n], "-p") == 0)
- *zeroPad = 1;
- else if (strcmp (argv[n], "-I") == 0)
- *invertFlag = 1;
- else if (strcmp (argv[n], "-L") == 0) {
- print_sos_lic ();
- exit (0);
- }
- else
- usage (0);
- }
-
- if (*f1 < 0.0 || *f1 >= 1.0 || *f2 < 0.0 || *f2 >= 1.0) {
- printf ("Cutoff frequency values must be between 0.0 and 1.0.\n");
- usage (1);
- }
-
- return;
- }
-